/*
Source Code License Agreement
Copyright (c) 2007, Matthew D. Wright. All rights reserved.

Matthew D. Wright grants to you a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable copyright license, to reproduce,
prepare derivative works of, publicly display, publicly perform, and
distribute this source code and such derivative works in source or
object code form without any attribution requirements.

The name "Matthew D. Wright" must not be used to endorse or promote 
products derived from the source code without prior written permission.

You agree to indemnify, hold harmless and defend Matthew D. Wright from 
and against any loss, damage, claims or lawsuits, including attorney's fees 
that arise or result from your use or distribution of the source code.

THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT
ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF
NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA
OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package net.nobien.webapis.google.utils
{
    
    import com.adobe.utils.DateUtil;
    import com.adobe.utils.StringUtil;
    import com.adobe.xml.syndication.atom.Atom10;
    import com.adobe.xml.syndication.atom.Author;
    import com.adobe.xml.syndication.atom.Category;
    import com.adobe.xml.syndication.atom.Contributor;
    import com.adobe.xml.syndication.atom.Entry;
    import com.adobe.xml.syndication.atom.Link;
    
    import net.nobien.webapis.google.blogger.Author;
    import net.nobien.webapis.google.blogger.Blog;
    import net.nobien.webapis.google.blogger.BlogPost;
    import net.nobien.webapis.google.blogger.Comment;
    import net.nobien.webapis.google.blogger.Contributor;
    
    /**
	 * The BloggerHelper class provides helper methods for processing
	 * responses from the Blogger Data API.
	 */
    public class BloggerHelper
    {
        
        private static function atomAuthorToAuthor( atomAuthor:com.adobe.xml.syndication.atom.Author ):net.nobien.webapis.google.blogger.Author
        {
            var author:net.nobien.webapis.google.blogger.Author = new net.nobien.webapis.google.blogger.Author();
            author.name = atomAuthor.name;
            author.email = atomAuthor.email;
            author.uri = atomAuthor.uri;
            return author;
        }
        
        private static function atomContributorToContributor( atomContributor:com.adobe.xml.syndication.atom.Contributor ):net.nobien.webapis.google.blogger.Contributor
        {
        	var contributor:net.nobien.webapis.google.blogger.Contributor = new net.nobien.webapis.google.blogger.Contributor();
        	contributor.name = atomContributor.name;
            contributor.email = atomContributor.email;
            contributor.uri = atomContributor.uri;
        	return contributor;
        }

        private static function atomEntryToBlog( atomEntry:Entry ):Blog
        {
        	var blog:Blog = new Blog();
        	blog.id = String( String( String( atomEntry.id.split(",")[1] ).split(":")[1] ).split(".")[0] ).split("-")[1];
            blog.published = atomEntry.published;
            blog.updated = atomEntry.updated;
            blog.title = atomEntry.title;
            
            var links:Array = atomEntry.links;
            for( var i:int = 0; i < links.length; i++ )
            {
                var link:Link = links[i];
                
                switch( link.rel )
                {
                    case "alertnate":
                        blog.alternateURL = link.href;
                        break;
                    
                    case "http://schemas.google.com/g/2005#feed":
                        blog.feedURL = link.href;
                        break;
                        
                    case "http://schemas.google.com/g/2005#post":
                        blog.postEndPoint = link.href;
                        break;
                        
                    case "self":
                        blog.preferredURL = link.href;
                        break;
                }   
            }
            
            for( i = 0; i < atomEntry.authors.length; i++ )
            {
                blog.authors.push( atomAuthorToAuthor( atomEntry.authors[i] ) );
            }
            
            for( i = 0; i < atomEntry.contributors.length; i++ )
            {
                blog.contributors.push( atomContributorToContributor( atomEntry.contributors[i] ) );
            }
        	
        	return blog;
        }
        
        private static function atomEntryToBlogPost( atomEntry:Entry ):BlogPost
        {
        	var blogPost:BlogPost = new BlogPost();
        	blogPost.id = String( String( String( atomEntry.id.split(",")[1] ).split(":")[1] ).split(".")[1] ).split("-")[1];
        	blogPost.blogID = String( String( String( atomEntry.id.split(",")[1] ).split(":")[1] ).split(".")[0] ).split("-")[1];
        	blogPost.published = atomEntry.published;
        	blogPost.updated = atomEntry.updated;
        	blogPost.title = atomEntry.title;
        	blogPost.content = atomEntry.content.value;
        	blogPost.contentType = atomEntry.content.type;
        	
        	for( var i:int = 0; i < atomEntry.links.length; i++ )
        	{
        	    var atomLink:Link = atomEntry.links[i];
				
        	    switch( atomLink.rel )
        	    {
        	        case "alternate":
        	            blogPost.alternateURL = atomLink.href;
        	            break;
        	            
        	        case "self":
        	            blogPost.preferredURL = atomLink.href;
        	            break;
        	            
        	        case "edit":
        	            blogPost.editEndPoint = atomLink.href;
        	            break;
        	            
        	        case "replies":
        	        	if( atomLink.type == "text/html" )
        	        		blogPost.commentAmt = int( atomLink.title.split(" ")[0] );
        	            break;
        	    }
        	}
        	
        	blogPost.commentFeedURL = "http://www.blogger.com/feeds/" + blogPost.blogID + "/" + blogPost.id + "/comments/default";
        	blogPost.commentPostEndPoint = "http://www.blogger.com/feeds/" + blogPost.blogID + "/" + blogPost.id + "/comments/default";
        	
        	for( i = 0; i < atomEntry.authors.length; i++ )
        	{
        		blogPost.authors.push( atomAuthorToAuthor( atomEntry.authors[i] ) );
        	}
        	
        	for( i = 0; i < atomEntry.contributors.length; i++ )
            {
                blogPost.contributors.push( atomContributorToContributor( atomEntry.contributors[i] ) );
            }
        	
        	for( i = 0; i < atomEntry.categories.length; i++ )
        	{
        		var category:Category = atomEntry.categories[i] as Category;
        		blogPost.categories.push( category.term );
        	}
        	
        	blogPost.draft = ( atomEntry.xml.toXMLString().indexOf( "<app:draft>yes</app:draft>" ) > -1 ) ? true : false;
            
        	return blogPost;
        }
        
        private static function atomEntryToComment( atomEntry:Entry, blogPostID:String ):Comment
        {
        	var comment:Comment = new Comment();
        	
        	comment.id = String( String( String( atomEntry.id.split(",")[1] ).split(":")[1] ).split(".")[1] ).split("-")[1];
        	comment.blogID = String( String( String( atomEntry.id.split(",")[1] ).split(":")[1] ).split(".")[0] ).split("-")[1];
        	comment.blogPostID = blogPostID;
        	comment.published = atomEntry.published;
        	comment.content = atomEntry.content.value;
        	comment.author = atomAuthorToAuthor( atomEntry.authors[0] );
        	
        	for( var i:int = 0; i < atomEntry.links.length; i++ )
        	{
        	    var atomLink:Link = atomEntry.links[i];
        	    
        	    if( atomLink.rel == "alternate" ) comment.url = atomLink.href;
        	    if( atomLink.rel == "edit" ) comment.editURL = atomLink.href;
        	}
        	
        	return comment;
        }
        
        /**
        * Parses a Blogger blog feed.
        * @param xmlStr String - Atom 1.0 feed data
        * @return Array An array of Blog objects
        */
        public static function parseBlogList( xmlStr:String ):Array
        {
            var atomFeed:Atom10 = new Atom10();
            atomFeed.parse( xmlStr );
            
            if( !atomFeed.entries ) return null;
            
            var blogs:Array = new Array();
            
            for( var i:int = 0; i < atomFeed.entries.length; i++ )
            {
                blogs.push( atomEntryToBlog( atomFeed.entries[i] ) );
            }
            
            return blogs;
        }
        
        /**
        * Parses a Blogger blog post.
        * @param xmlStr String - Atom 1.0 entry data
        * @return BlogPost A BlogPost object
        */
        public static function parseBlogPost( xmlStr:String ):BlogPost
        {
        	var atomEntry:Entry = new Entry( new XMLList( xmlStr ) );
        	return atomEntryToBlogPost( atomEntry );
        }
        
        /**
        * Parses a Blogger blog post feed.
        * @param xmlStr String - Atom 1.0 feed data
        * @return Array An array of BlogPost objects
        */
        public static function parseBlogPostList( xmlStr:String ):Array
        {
        	var atomFeed:Atom10 = new Atom10();
            atomFeed.parse( xmlStr );

            if( !atomFeed.entries ) return null;
        	
        	var posts:Array = new Array();
        	
        	for( var i:int = 0; i < atomFeed.entries.length; i++ )
            {
            	posts.push( atomEntryToBlogPost( atomFeed.entries[i] ) );
            }
        	
        	return posts;
        }
        
        /**
        * Parses a Blogger comment entry.
        * @param xmlStr String - Atom 1.0 entry data
        * @return Comment A Comment object
        */
        public static function parseComment( xmlStr:String, blogPostID:String ):Comment
        {
        	var atomEntry:Entry = new Entry( new XMLList( xmlStr ) );
        	return atomEntryToComment( atomEntry, blogPostID );
        }
        
        /**
        * Parses a Blogger comment feed.
        * @param xmlStr String - Atom 1.0 feed data
        * @return Array An array of Comment objects
        */
        public static function parseCommentList( xmlStr:String ):Array
        {
        	var atomFeed:Atom10 = new Atom10();
            atomFeed.parse( xmlStr );
            
            var blogPostID:String = String( atomFeed.feedData.id.split(".")[2] ).substr( 4 );
            
            if( !atomFeed.entries ) return null;
            
            var comments:Array = new Array();
            
        	for( var i:int = 0; i < atomFeed.entries.length; i++ )
            {
            	comments.push( atomEntryToComment( atomFeed.entries[i], blogPostID ) );
            }
            
        	return comments;
        }
        
        /**
        * Serializes a BlogPost object.
        * @param blogPost BlogPost - The blog post to serialize
        * @return String An Atom entry XML string
        */
        public static function serializeBlogPost( blogPost:BlogPost ):String
        {
        	var xmlStr:String = "<entry xmlns='http://www.w3.org/2005/Atom'>";
        	
        	if( blogPost.id != null ) xmlStr += "<id>tag:blogger.com,1999:blog-" + blogPost.blogID + ".post-" + blogPost.id + "</id>";
        	if( blogPost.published != null ) xmlStr += "<published>" + DateUtil.toW3CDTF( blogPost.published ) + "</published>";
        	if( blogPost.updated != null ) xmlStr += "<updated>" + DateUtil.toW3CDTF( blogPost.updated ) + "</updated>";
        	
        	for( var i:int = 0; i < blogPost.categories.length; i++ )
        	{
        		var category:String = blogPost.categories[i] as String;
        		xmlStr += "<category scheme='http://www.blogger.com/atom/ns#' term='" + category + "' />";
        	}
        	
        	xmlStr += "<title type='text'>" + encodeSpecialChars( blogPost.title ) + "</title>";
        	
        	if( blogPost.draft ) xmlStr += "<app:control xmlns:app='http://purl.org/atom/app#'><app:draft>yes</app:draft></app:control>";
        	
        	xmlStr += "<content type='" + blogPost.contentType + "'>" + encodeSpecialChars( blogPost.content ) + "</content>";
        	
        	if( blogPost.alternateURL != null ) xmlStr += "<link rel='alternate' type='text/html' href='" + blogPost.alternateURL + "' title='" + encodeSpecialChars( blogPost.title ) + "'/>";
        	if( blogPost.commentFeedURL != null ) xmlStr += "<link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=" + blogPost.blogID + "&amp;postID=" + blogPost.id + "' title='" + blogPost.commentAmt + " Comments'/>";
        	if( !blogPost.draft ) xmlStr += "<link rel='replies' type='application/atom+xml' href='http://aircmr.blogspot.com/feeds/" + blogPost.id + "/comments/default' title='Post Comments' />";
        	if( blogPost.preferredURL != null ) xmlStr += "<link rel='self' type='application/atom+xml' href='" + blogPost.preferredURL + "' />";
        	if( blogPost.editEndPoint != null ) xmlStr += "<link rel='edit' type='application/atom+xml' href='" + blogPost.editEndPoint + "' />";
        	
        	for( i = 0; i < blogPost.authors.length; i++ )
        	{
        		var author:net.nobien.webapis.google.blogger.Author = blogPost.authors[i] as net.nobien.webapis.google.blogger.Author;
        		
        		xmlStr += "<author>";
        		xmlStr += "<name>" + author.name + "</name>";
        		
        		if( author.email != null ) xmlStr += "<email>" + author.email + "</email>";
        		if( author.uri != null ) xmlStr += "<uri>" + author.uri + "</uri>";
        		
        		xmlStr += "</author>";
        	}
        	
        	for( i = 0; i < blogPost.contributors.length; i++ )
        	{
        		var contributor:net.nobien.webapis.google.blogger.Contributor = blogPost.contributors[i] as net.nobien.webapis.google.blogger.Contributor;
        		
        		xmlStr += "<contributor>";
        		xmlStr += "<name>" + contributor.name + "</name>";
        		
        		if( contributor.email != null ) xmlStr += "<email>" + contributor.email + "</email>";
        		if( contributor.uri != null ) xmlStr += "<uri>" + contributor.uri + "</uri>";
        		
        		xmlStr += "</contributor>";
        	}
        	
        	xmlStr += "</entry>";
        	
        	return xmlStr;
        }
        
        /**
        * Serializes a Comment object.
        * @param comment Comment - The comment to serialize
        * @return String An Atom entry XML string
        */
        public static function serializeComment( comment:Comment ):String
        {
        	var xmlStr:String = "<entry xmlns='http://www.w3.org/2005/Atom'>";
        	
        	xmlStr += "<content type='html'>" + encodeSpecialChars( comment.content ) + "</content>";
        	
        	xmlStr += "<author>";
    		xmlStr += "<name>" + comment.author.name + "</name>";
    		
    		if( comment.author.email != null ) xmlStr += "<email>" + comment.author.email + "</email>";
    		if( comment.author.uri != null ) xmlStr += "<uri>" + comment.author.uri + "</uri>";
    		
    		xmlStr += "</author>";
        	
        	xmlStr += "</entry>";
        	
        	return xmlStr;
        }
        
        /**
        * Builds a Blogger query string
        * @param categories Array - An optional Array of category names
        * @param updatedMin Date - An optional Date specifying the oldest updated date
        * @param updatedMax Date - An optional Date specifying the youngest updated date
        * @param publishedMin Date - An optional Date specifying the oldest publish date
        * @param publishedMax Date - An optional Date specifying the youngest publish date
        * @param orderBy String - An optional String to specify the ordering of the results
        * @param maxResults int - An optional int specifying the maximum amount of results
        * @param startIndex int - An optional int specifying the start index
        * @return String A query string
        */
        public static function buildQueryString( categories:Array = null,
        										 updatedMin:Date = null,
        										 updatedMax:Date = null, 
        										 publishedMin:Date = null,
        										 publishedMax:Date = null, 
        										 orderBy:String = null, 
        										 maxResults:int = -1, 
        										 startIndex:int = -1 ):String
		{
			var qStr:String = "";
			
			if( categories != null )
			{
				qStr += "/-";
				for( var i:int = 0; i < categories.length; i++ )
				{
					qStr += "/" + categories[i];
				}
			}
			
			if( updatedMin != null ||
				updatedMax != null ||
				publishedMin != null ||
				publishedMax != null ||
				orderBy != null ||
				maxResults != -1 ||
				startIndex != -1 )
			{
				var firstVar:Boolean = true;
			}
			
			if( updatedMin != null )
			{
				if( firstVar )
				{
					qStr += "?";
					firstVar = false;
				}
				else
				{
					qStr += "&";
				}
				qStr += "updated-min=" + DateUtil.toW3CDTF( updatedMin );
			}
			
			if( publishedMin != null ) 
			{
				if( firstVar )
				{
					qStr += "?";
					firstVar = false;
				}
				else
				{
					qStr += "&";
				}
				qStr += "published-min=" + DateUtil.toW3CDTF( publishedMin );
			}
			
			if( updatedMax != null )
			{
				if( firstVar )
				{
					qStr += "?";
					firstVar = false;
				}
				else
				{
					qStr += "&";
				}
				qStr += "updated-max=" + DateUtil.toW3CDTF( updatedMax );
			}
			
			if( publishedMax != null ) 
			{
				if( firstVar )
				{
					qStr += "?";
					firstVar = false;
				}
				else
				{
					qStr += "&";
				}
				qStr += "published-max=" + DateUtil.toW3CDTF( publishedMax );
			}
			
			if( orderBy != null )
			{
				if( firstVar )
				{
					qStr += "?";
					firstVar = false;
				}
				else
				{
					qStr += "&";
				}
				qStr += "orderby=" + orderBy;
			}
			
			if( maxResults != -1 )
			{
				if( firstVar )
				{
					qStr += "?";
					firstVar = false;
				}
				else
				{
					qStr += "&";
				}
				qStr += "max-results=" + maxResults;
			} 
			
			if( startIndex != -1 )
			{
				if( firstVar )
				{
					qStr += "?";
					firstVar = false;
				}
				else
				{
					qStr += "&";
				}
				qStr += "start-index=" + startIndex;
			} 
			
			return qStr;

		}
        
        /**
        * Encodes special characters as HTML entities.
        * @param str String - A content string
        * @return String The encoded content string
        */
        public static function encodeSpecialChars( str:String ):String
        {
        	str = StringUtil.replace( str, "&", "&amp;" );
			str = StringUtil.replace( str, "<", "&lt;" );
			str = StringUtil.replace( str, ">", "&gt;" );
			str = StringUtil.replace( str, '"', "&quot;" );
			str = StringUtil.replace( str, "'", "&apos;" );
			str = StringUtil.replace( str, "'", "&rsquo;" );
			str = StringUtil.replace( str, "'", "&lsquo;" );
			return str;
        }
        
    }
}